Implement GdkKeymap using libxkbcommon
authorKristian Høgsberg <krh@bitplanet.net>
Fri, 7 Jan 2011 17:10:41 +0000 (12:10 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Sat, 5 Feb 2011 21:11:55 +0000 (16:11 -0500)
gdk/wayland/gdkdevice-wayland.h
gdk/wayland/gdkdevicemanager-wayland.c
gdk/wayland/gdkdisplay-wayland.c
gdk/wayland/gdkkeys-wayland.c
gdk/wayland/gdkprivate-wayland.h

index 88fac43a6e0cff332c95287ca29ee90c11bf8164..a8d4dd99d0645b9315d4e37a7f25dbf586a38288 100644 (file)
@@ -20,8 +20,8 @@
 #ifndef __GDK_DEVICE_CORE_H__
 #define __GDK_DEVICE_CORE_H__
 
+#include <stdint.h>
 #include <gdk/gdkdeviceprivate.h>
-#include <X11/extensions/XKBcommon.h>
 
 G_BEGIN_DECLS
 
@@ -45,7 +45,6 @@ struct _GdkWaylandDevice
   GdkWindow *pointer_focus;
   GdkWindow *keyboard_focus;
   struct wl_input_device *device;
-  struct xkb_desc *xkb;
   int32_t x, y, surface_x, surface_y;
 };
 
index c432ec7ea8e89b391646f6da1b9c762443d709b9..d1543f9a70dabe914e70fe7dc78aedcab3cee2c6 100644 (file)
@@ -28,6 +28,7 @@
 #include "gdkprivate-wayland.h"
 #include "gdkeventsource.h"
 
+#include <X11/extensions/XKBcommon.h>
 
 static void    gdk_device_manager_core_finalize    (GObject *object);
 
@@ -116,6 +117,8 @@ input_handle_key(void *data, struct wl_input_device *input_device,
   GdkWaylandDevice *device = data;
   GdkEvent *event;
   uint32_t code, modifier, level;
+  struct xkb_desc *xkb;
+  GdkKeymap *keymap;
 
   event = gdk_event_new (state ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
   event->key.window = g_object_ref (device->keyboard_focus);
@@ -125,16 +128,19 @@ input_handle_key(void *data, struct wl_input_device *input_device,
   event->key.group = 0;
   event->key.hardware_keycode = key;
 
-  code = key + device->xkb->min_key_code;
+  keymap = gdk_keymap_get_for_display (device->display);
+  xkb = _gdk_wayland_keymap_get_xkb_desc (keymap);
+
+  code = key + xkb->min_key_code;
 
   level = 0;
   if (device->modifiers & ShiftMask &&
-      XkbKeyGroupWidth(device->xkb, code, 0) > 1)
+      XkbKeyGroupWidth(xkb, code, 0) > 1)
     level = 1;
 
-  event->key.keyval = XkbKeySymEntry(device->xkb, code, level, 0);
+  event->key.keyval = XkbKeySymEntry(xkb, code, level, 0);
 
-  modifier = device->xkb->map->modmap[code];
+  modifier = xkb->map->modmap[code];
   if (state)
     device->modifiers |= modifier;
   else
@@ -269,10 +275,15 @@ static void
 update_modifiers(GdkWaylandDevice *device, struct wl_array *keys)
 {
   uint32_t *k, *end;
+  GdkKeymap *keymap;
+  struct xkb_desc *xkb;
+
+  keymap = gdk_keymap_get_for_display (device->display);
+  xkb = _gdk_wayland_keymap_get_xkb_desc (keymap);
 
   end = keys->data + keys->size;
   for (k = keys->data; k < end; k++)
-    device->modifiers |= device->xkb->map->modmap[*k];
+    device->modifiers |= xkb->map->modmap[*k];
 
   fprintf (stderr, "modifiers: 0x%x\n", device->modifiers);
 }
@@ -335,7 +346,6 @@ gdk_device_manager_core_add_device (GdkDeviceManager *device_manager,
   GdkDisplay *display;
   GdkDeviceManagerCore *device_manager_core =
     GDK_DEVICE_MANAGER_CORE(device_manager);
-  struct xkb_rule_names names;
   GdkWaylandDevice *device;
 
   device = g_new0 (GdkWaylandDevice, 1);
@@ -366,13 +376,6 @@ gdk_device_manager_core_add_device (GdkDeviceManager *device_manager,
   GDK_DEVICE_CORE (device->keyboard)->device = device;
   device->device = wl_device;
 
-  names.rules = "evdev";
-  names.model = "pc105";
-  names.layout = "us";
-  names.variant = "";
-  names.options = "";
-  device->xkb = xkb_compile_keymap_from_rules(&names);
-
   wl_input_device_add_listener(device->device,
                               &input_device_listener, device);
 
index fefa1f55cdc77e721f340c2f8ee47efd66380dba..34740d18d415b1b274fa63a376c8b92b1eecdc5f 100644 (file)
@@ -709,10 +709,7 @@ gdk_wayland_display_get_keymap (GdkDisplay *display)
   display_wayland = GDK_DISPLAY_WAYLAND (display);
 
   if (!display_wayland->keymap)
-    display_wayland->keymap =
-      g_object_new (_gdk_wayland_keymap_get_type(), NULL);
-
-  display_wayland->keymap->display = display;
+    display_wayland->keymap = _gdk_wayland_keymap_new (display);
 
   return display_wayland->keymap;
 }
index 87b139814adc05272f32ebe00e163ea5218909e1..f18bf0e291d0c84b68fbf7ce95d0585b173b5aff 100644 (file)
@@ -49,6 +49,7 @@ typedef struct _GdkWaylandKeymapClass     GdkWaylandKeymapClass;
 struct _GdkWaylandKeymap
 {
   GdkKeymap parent_instance;
+  struct xkb_desc *xkb;
 };
 
 struct _GdkWaylandKeymapClass
@@ -57,7 +58,7 @@ struct _GdkWaylandKeymapClass
 };
 
 #define GDK_TYPE_WAYLAND_KEYMAP          (_gdk_wayland_keymap_get_type ())
-#define GDK_WAYLAND_KEYMAP(object)       (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeyMap))
+#define GDK_WAYLAND_KEYMAP(object)       (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap))
 #define GDK_IS_WAYLAND_KEYMAP(object)    (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP))
 
 G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP)
@@ -94,39 +95,190 @@ gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap)
 
 static gboolean
 gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
-                                      guint          keyval,
-                                      GdkKeymapKey **keys,
-                                      gint          *n_keys)
+                                          guint          keyval,
+                                          GdkKeymapKey **keys,
+                                          gint          *n_keys)
 {
-  return FALSE;
+  GArray *retval;
+  uint32_t keycode;
+  struct xkb_desc *xkb;
+
+  xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
+  keycode = xkb->min_key_code;
+
+  retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+
+  for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++)
+    {
+      gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
+
+      gint group = 0;
+      gint level = 0;
+      gint total_syms = XkbKeyNumSyms (xkb, keycode);
+      gint i = 0;
+      uint32_t *entry;
+
+      /* entry is an array with all syms for group 0, all
+       * syms for group 1, etc. and for each group the
+       * shift level syms are in order
+       */
+      entry = XkbKeySymsPtr (xkb, keycode);
+
+      for (i = 0; i < total_syms; i++)
+       {
+         /* check out our cool loop invariant */
+         g_assert (i == (group * max_shift_levels + level));
+
+         if (entry[i] == keyval)
+           {
+             /* Found a match */
+             GdkKeymapKey key;
+
+             key.keycode = keycode;
+             key.group = group;
+             key.level = level;
+
+             g_array_append_val (retval, key);
+
+             g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
+                       keyval);
+           }
+
+         level++;
+
+         if (level == max_shift_levels)
+           {
+             level = 0;
+             group++;
+           }
+       }
+    }
+
+  *n_keys = retval->len;
+  *keys = (GdkKeymapKey *) g_array_free (retval, FALSE);
+
+  return *n_keys > 0;
 }
 
 static gboolean
 gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
-                                       guint          hardware_keycode,
-                                       GdkKeymapKey **keys,
-                                       guint        **keyvals,
-                                       gint          *n_entries)
+                                           guint          hardware_keycode,
+                                           GdkKeymapKey **keys,
+                                           guint        **keyvals,
+                                           gint          *n_entries)
 {
-  return FALSE;
+  GArray *key_array;
+  GArray *keyval_array;
+  struct xkb_desc *xkb;
+  gint max_shift_levels;
+  gint group = 0;
+  gint level = 0;
+  gint total_syms;
+  gint i;
+  uint32_t *entry;
+
+  g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
+  g_return_val_if_fail (n_entries != NULL, FALSE);
+
+  xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
+
+  if (hardware_keycode < xkb->min_key_code ||
+      hardware_keycode > xkb->max_key_code)
+    {
+      if (keys)
+       *keys = NULL;
+      if (keyvals)
+       *keyvals = NULL;
+
+      *n_entries = 0;
+      return FALSE;
+    }
+
+  if (keys)
+    key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
+  else
+    key_array = NULL;
+
+  if (keyvals)
+    keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
+  else
+    keyval_array = NULL;
+
+  /* See sec 15.3.4 in XKB docs */
+  max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode);
+  total_syms = XkbKeyNumSyms (xkb, hardware_keycode);
+
+  /* entry is an array with all syms for group 0, all
+   * syms for group 1, etc. and for each group the
+   * shift level syms are in order
+   */
+  entry = XkbKeySymsPtr (xkb, hardware_keycode);
+
+  for (i = 0; i < total_syms; i++)
+    {
+      /* check out our cool loop invariant */
+      g_assert (i == (group * max_shift_levels + level));
+
+      if (key_array)
+       {
+         GdkKeymapKey key;
+
+         key.keycode = hardware_keycode;
+         key.group = group;
+         key.level = level;
+
+         g_array_append_val (key_array, key);
+       }
+
+      if (keyval_array)
+       g_array_append_val (keyval_array, entry[i]);
+
+      ++level;
+
+      if (level == max_shift_levels)
+       {
+         level = 0;
+         ++group;
+       }
+    }
+
+  *n_entries = 0;
+
+  if (keys)
+    {
+      *n_entries = key_array->len;
+      *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE);
+    }
+
+  if (keyvals)
+    {
+      *n_entries = keyval_array->len;
+      *keyvals = (guint*) g_array_free (keyval_array, FALSE);
+    }
+
+  return *n_entries > 0;
 }
 
 static guint
 gdk_wayland_keymap_lookup_key (GdkKeymap          *keymap,
-                          const GdkKeymapKey *key)
+                              const GdkKeymapKey *key)
 {
-  return 0;
+  struct xkb_desc *xkb;
+
+  xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
+
+  return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
 }
 
 static gboolean
 gdk_wayland_keymap_translate_keyboard_state (GdkKeymap       *keymap,
-                                        guint            hardware_keycode,
-                                        GdkModifierType  state,
-                                        gint             group,
-                                        guint           *keyval,
-                                        gint            *effective_group,
-                                        gint            *level,
-                                        GdkModifierType *consumed_modifiers)
+                                            guint            hardware_keycode,
+                                            GdkModifierType  state,
+                                            gint             group,
+                                            guint           *keyval,
+                                            gint            *effective_group,
+                                            gint            *level,
+                                            GdkModifierType *consumed_modifiers)
 {
   return FALSE;
 }
@@ -134,13 +286,13 @@ gdk_wayland_keymap_translate_keyboard_state (GdkKeymap       *keymap,
 
 static void
 gdk_wayland_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
-                                     GdkModifierType *state)
+                                         GdkModifierType *state)
 {
 }
 
 static gboolean
 gdk_wayland_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
-                                     GdkModifierType *state)
+                                         GdkModifierType *state)
 {
   return FALSE;
 }
@@ -169,3 +321,27 @@ static void
 _gdk_wayland_keymap_init (GdkWaylandKeymap *keymap)
 {
 }
+
+GdkKeymap *
+_gdk_wayland_keymap_new (GdkDisplay *display)
+{
+  GdkWaylandKeymap *keymap;
+  struct xkb_rule_names names;
+
+  keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL);
+  GDK_KEYMAP (keymap)->display = display;
+
+  names.rules = "evdev";
+  names.model = "pc105";
+  names.layout = "us";
+  names.variant = "";
+  names.options = "";
+  keymap->xkb = xkb_compile_keymap_from_rules(&names);
+
+  return GDK_KEYMAP (keymap);
+}
+
+struct xkb_desc *_gdk_wayland_keymap_get_xkb_desc (GdkKeymap *keymap)
+{
+  return GDK_WAYLAND_KEYMAP (keymap)->xkb;
+}
index ef13fea1baf66c519be2580172603d0e1d940c5d..dcd9fa92273240d4ad76eb392fff5cb499277f4e 100644 (file)
@@ -46,7 +46,9 @@
 #define GDK_WINDOW_IS_WAYLAND(win)    (GDK_IS_WINDOW_IMPL_WAYLAND (((GdkWindow *)win)->impl))
 
 GType      _gdk_wayland_window_get_type            (void);
-GType      _gdk_wayland_keymap_get_type            (void);
+
+GdkKeymap *_gdk_wayland_keymap_new (GdkDisplay *display);
+struct xkb_desc *_gdk_wayland_keymap_get_xkb_desc (GdkKeymap *keymap);
 
 GdkCursor *_gdk_wayland_display_get_cursor_for_type (GdkDisplay    *display,
                                                     GdkCursorType  cursor_type);